<template>
  <div>
    <ul>
      <li>username: {{ userInfo.username }}</li>
      <li>email: {{ userInfo.email }}</li>
      <li>avatar: {{ userInfo.avatar }}</li>
    </ul>
    <div class="drag-box" ref="dragRef">
      <input
        ref="fileUploadRef"
        type="file"
        name="file"
        @change="handleFileChange"
      />
    </div>
    <el-progress
      :text-inside="true"
      :stroke-width="26"
      :percentage="chunkProgress"
    ></el-progress>
    <el-progress
      :text-inside="true"
      :stroke-width="26"
      :percentage="chunkIdsProgress"
    ></el-progress>
    <template v-for="task in taskFormList">
      {{ task.index }} :
      <el-progress
        :percentage="task.progress"
        :key="task.index"
        :status="
          task.error === 3
            ? 'exception'
            : task.progress === 100
            ? 'success'
            : 'format'
        "
      ></el-progress>
    </template>
    <el-progress
      :text-inside="true"
      :stroke-width="26"
      :percentage="uploadProgress"
    ></el-progress>

    <el-button @click="uploadFile">上传</el-button>
  </div>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import { userInfoType } from "@type/user";
import { chunkHashType, checkFileType } from "@/type/file";
import {
  isGif,
  isJpg,
  isPng,
  calculateHashWorker,
  calculateHashIdle,
  calculateHashSample,
  DEFAULT_CHUNK_SIZE,
} from "@/utils";

type formDataArray = Array<{
  form: FormData;
  error: number;
  progress: number;
  index: number;
}>;

@Component
class Index extends Vue {
  userInfo: userInfoType = {
    username: "",
    email: "",
    avatar: "",
  };
  created() {
    this.$http.get("/user/info").then((res: any) => {
      if (res.code === 0) {
        this.userInfo = res.data;
      }
    });
  }

  uploadProgress: number = 0;
  mounted() {
    const dragBoxRef = this.$refs.dragRef as HTMLElement;
    // 拖拽放置进入目标上触发
    dragBoxRef.addEventListener("dragover", (e: Event) => {
      dragBoxRef.style.borderColor = "red";
      e.preventDefault();
    });
    // 拖拽离开时触发
    dragBoxRef.addEventListener("dragleave", (e: Event) => {
      dragBoxRef.style.borderColor = "#ccc";
      e.preventDefault();
    });
    // 拖拽放下时触发
    dragBoxRef.addEventListener("drop", (e: any) => {
      this.file = e.dataTransfer.files[0];
      e.preventDefault();
    });
  }
  chunkProgress: number = 0;
  chunkIdsProgress: number = 0;
  // 文件
  file: File | string = "";
  async handleFileChange(e: any) {
    const [file] = e.target.files;

    if (!file) {
      return;
    }

    // const isgif = await isGif(file);
    // const ispng = await isPng(file);
    // const isjpg = await isJpg(file);

    // if (!isgif && !ispng && !isjpg) {
    //   let fileUploadRef = this.$refs.fileUploadRef as any;
    //   fileUploadRef.value = "";
    //   console.dir(fileUploadRef);
    //   fileUploadRef.outerHTML = fileUploadRef.outerHTML;
    //   return (this.file = new Blob());
    // }
    let time = Number(new Date());
    const chunkData = await calculateHashWorker(file, (data: any) => {
      this.chunkProgress = data.progress;
    });

    let endTime = Number(new Date());
    console.log(chunkData, "最终数据", endTime - time);
    time = endTime;

    // const chunkIdleData = await calculateHashIdle(file, (data: any) => {
    //   this.chunkIdsProgress = data.progress;
    // });

    // endTime = Number(new Date());
    // console.log(chunkIdleData, "最终数据", endTime - time);
    // time = endTime;

    // const chunkSample = await calculateHashSample(file);

    // endTime = Number(new Date());
    // console.log(chunkSample, "最终数据", endTime - time);
    // time = endTime;
    this.file = file;
  }

  getFromParmas(
    hash: string,
    chunks: Array<any>,
    uploadedList: Array<string>
  ): { finishProgress: number; fromParmas: formDataArray } {
    let finishProgress = 0;
    const fromParmas: formDataArray = [];
    chunks.forEach((chunk: any, index: number) => {
      let hashName = hash + "-" + index;
      if (uploadedList.includes(hashName)) {
        finishProgress++;
        return;
      }
      const form = new FormData();
      form.append("fileName", hashName);
      form.append("chunk", chunk.file);
      form.append("hash", hash);
      fromParmas.push({ form, error: 0, progress: 0, index });
    });

    finishProgress = Number(
      ((finishProgress * 100) / chunks.length).toFixed(2)
    );
    return { finishProgress, fromParmas };
  }

  mergeFile(ext: string | undefined, hash: string, size = DEFAULT_CHUNK_SIZE) {
    this.$http.post("/mergefile", { ext, size, hash }).then((res) => {
      console.log(res);
    });
  }

  async checkFileUpload(
    ext: string | undefined,
    hash: string
  ): Promise<checkFileType> {
    let { data } = await this.$http.post("/checkfile", { ext, hash });
    return { ...data };
  }
  taskFormList: formDataArray = [];

  async sendReuest(taskFormList: formDataArray, limt: number = 3) {
    return new Promise((resolve, reject) => {
      const len = taskFormList.length;
      let counter = 0;
      let isStop = false;
      const start = async () => {
        const formData = taskFormList.shift();
        if (formData && !isStop) {
          try {
            await this.$http.post("/uploadfile", formData.form, {
              onUploadProgress: (progress: any) => {
                console.log(formData.index);
                this.taskFormList[formData.index].progress = Number(
                  ((progress.loaded / progress.total) * 100).toFixed(2)
                );
              },
            });

            if (counter === len - 1) {
              resolve(true);
            } else {
              counter++;
              start();
            }
          } catch (error) {
            // 这里进行错误重试
            if (this.taskFormList[formData.index].error < 3) {
              this.taskFormList[formData.index].error++;
              taskFormList.unshift(formData);
              start();
            } else {
              isStop = true;
              reject();
            }
          }
        }
      };

      while (limt > 0) {
        start();
        limt -= 1;
      }
    });
  }

  async uploadFile() {
    if (!this.file) {
      return this.$message.error("请选择图片");
    }

    const hashWorkData: chunkHashType = await calculateHashWorker(
      this.file,
      (data: chunkHashType) => {
        this.chunkProgress = data.progress;
      }
    );
    const ext = (this.file as File).name.split(".").pop();
    const { hash, chunks } = hashWorkData;
    // 判断是否已经上传过
    let { uploaded, uploadedList }: checkFileType = await this.checkFileUpload(
      ext,
      hash
    );

    if (uploaded) {
      return this.$message.success("秒传成功");
    }

    const { finishProgress, fromParmas } = this.getFromParmas(
      hash,
      chunks,
      uploadedList
    );
    this.taskFormList = JSON.parse(JSON.stringify(fromParmas));
    console.log("当前已完成进度:" + finishProgress + "%");
    if (finishProgress === 100) {
      return this.mergeFile(ext, hash);
    }
    await this.sendReuest(fromParmas);
    this.mergeFile(ext, hash);
  }
}

export default Index;
</script>

<style lang="scss">
.drag-box {
  height: 100px;
  line-height: 100px;
  text-align: center;
  border: 2px dashed #ccc;
}
</style>
